<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>class</title>
</head>

<body>
    <script>
        /* 1.实例化类——构造函数
        class Car {
            constructor(brank, color, money) { //初始化都在构造函数里进行
                //console.log(args)
                this.brank = brank
                this.color = color
                this.money = money
                this.getInfo = () => {
                    console.log(`品牌：${this.brank}，颜色：${this.color}，钱：${this.money}；`)
                }
            }
        }
        let myCar = new Car("特斯拉", "红", 150)
        // console.log(myCar)
        myCar.getInfo() */
        //2.实例化类——声明属性 
        /* class Book {
            title = '心里咨询全集'
            price = 25
            getInfo() {
                console.log(`书名:《${this.title}》，价格:${this.price}`)
            }
        }
        let myBook = new Book()
        console.log(myBook)
        myBook.getInfo() */

        /* var mytitle = "心里咨询全集"
        var myprice = 29
        class Book {
            title = mytitle
            price = myprice
            getInfo() {
                console.log(`书名:《${this.title}》，价格:${this.price}`)
            }
        }
        let myBook1 = new Book()
        console.log(myBook1)
        mytitle = "蓝房子"
        myprice = 25
        let myBook2 = new Book()
        console.log(myBook2) */
        /* class Book {
            static num = 5 //不会出现在实例中
            constructor(title, price) {
                this.title = title
                this.price = price
                // this.getInfo() //写在这里，初始化的时候就会直接调用

            }
            title = "默认书名"
            price = 1
            getInfo() {
                console.log(`书名:《${this.title}》，价格:${this.price}`)
            }
        }
        let myBook3 = new Book()
        console.log(myBook3) //undefined*2 也就是说有构造函数会覆盖之前定义的
        let myBook4 = new Book("蓝房子", 55)
        console.log(myBook4)
        //声明静态属性
        Book.name = "默认名字"
        Book.date = "020-6-4"
        //静态属性可以这样访问到，但不会出现在实例里
        console.log(Book.name + "  " + Book.date)
        let myBook5 = new Book("aaa", 5)
        console.log(myBook5) */
        /*
        一个类必须有constructor方法，如果没有显式定义，一个空的constructor方法会被默认添加。constructor方法默认返回实例对象（即this），完全可以指定返回另外一个对象
        */
        //3. get / set方法1： 在类里声明方法
        /* class Book {
            constructor(title, price) {
                this._title = title
                this._price = price
            }
            getInfo() {
                console.log(`书名:《${this._title}》，价格:${this._price}`)
            }
            //get set方法;自身属性名前面加一个下划线，以免与get/set方法同名造成递归——栈溢出
            get title() {
                return this._title
            }
            set title(t) {
                console.log("调用了set-title方法")
                this._title = t
            }
            get price() {
                return `这本书的价格是${this._price}`
            }
            set price(p) {
                console.log("调用了set-price方法")
                this._price = p
            }
        }
        let myBook6 = new Book()
        myBook6.title = "幸福来临时"
        myBook6.price = 12
        console.log(myBook6.price) */
        /*4.get/set方法：对象，通过.defineProperty设置  
        var Book = {
             _title: '',
             _prict: 0,
             getInfo: () => {
                 console.log(`书名:《${this._title}》，价格:${this._price}`)
             }
         }
         Object.defineProperty(Book, 'title', { */
        /*  get: () => {
             console.log("get方法")
             return this._title //箭头函数里没有this,这个this指向Window
         },
         set: (t) => {
             console.log("set方法")
             console.log(this)
             this._title = t
         } */
        /* get: function () {
                console.log("get方法")
                return this._title
            },
            set: function (t) {
                console.log("set方法")
                this._title = t
            }
        })
        Book.title = "幸福来临时" //set
        //console.log(Book)
        console.log(Book.title) //get */

        /* 5.小例子
        var born_year = prompt("请输入出生年份：")
        class p_age {
            _age = 18
            get age() {
                return this._age
            }
            set age(y) {
                if (isNaN(y) || y.length != 4) return //验证一下
                this._age = new Date().getFullYear() - y
            }
        }
        let myAge = new p_age()
        myAge.age = born_year
        document.write(`你今年${myAge._age}岁`) */
        /* 6. name属性
        class Person {
            name = "aaa" //实际上，name是类的一个默认值，值为该类的名字，Person.name输出Person
        }
        const Human = class P {
            //Human.name 输出P
        }
        const Human1 = class {
            //Human1.name 输出Human1
        } */
        /*7.new.target属性 
        function Car() {
            if (new.target !== Car) { //相当于 if(!(this instanceof Car))
                throw Error("必须使用关键字调用")

            } else {
                console.log(new.target)
            }
        }
        new Car()
        Car() */
        //8.模拟构造函数
        // 当用new关键字调用函数的时候 发生了什么 为什么会获得一个新的对象
        // 1. 创建一个空的对象
        // 2. 把构造函数的prototype属性 作为空对象的原型
        // 3. this赋值为这个空对象
        // 4. 执行函数
        // 5. 如果函数没有返回值 则返回this[返回之前那个空对象]
        function Constructor(fn, args) {
            var _this = Object.create(fn.prototype); //_this.__proto__=fn.prototype

            var res = fn.apply(_this, args);

            return res ? res : _this;
        }

        function Person(name, age) {
            this.name = name;
            this.age = age;
        }

        Person.prototype.say = function () {
            console.log('我叫' + this.name);
        }

        var person = Constructor(Person, ['张三', 12]);

        //console.log(person);
        Person("No.1", 20)
        console.log(window.name + "  " + window.age) //No.1  20
        let P1 = new Person("No.2", 22)
        console.log(P1.name + "  " + P1.age) //No.2  22
        let p2 = Constructor(Person, ["No.3", 30])
        console.log(p2.name + "  " + p2.age) //No.3 30
    </script>
</body>

</html>